"""Module providing
:socket 通讯
:sqlite3  OperationalError 错误类型
:时间
:json解析
:re
:datetime
:path拼接
:winreg修改
:requests
:urllib3
:BackgroundScheduler定时器
:log
:数据库类"""
from datetime import datetime
import socket
from sqlite3 import OperationalError
import time
import json
import re
from pathlib import Path
import winreg
import requests
import urllib3
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
#BackgroundScheduler
from loguru import logger
import DBHelp_Sqlite
from concurrent.futures import ThreadPoolExecutor
import threading
import traceback
import pandas as pd
from flask import Flask, render_template, request, jsonify
#from flask_caching import Cache
import numpy as np
#import pyodbc
from waitress import serve
import signal
import os

# 设置版本信息
version = '1.2.5'
# 设置版权信息
authors = '傅永'
# 设置文件说明
description = '平台与纽贝尔联动自动切换'

# 本人python == 3.12.8,虚拟环境名：py3122
# 生成requirements.txt文件：pip freeze > requirements.txt
# 安装requirements.txt依赖：pip install -r requirements.txt
# 打包exe文件命令：
# Pyinstaller -F -i xx.ico main.py
'''
    @作者：潍坊 傅永
    @版本:2025-01-05 17:00
    @功能：



'''
MAX_CONNECT_RETRIES = 5
CONNECT_RETRY_DELAY = 10
# 禁用特定警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


DATABASE_FILENAME = Path('data').joinpath("test.db")
CFG_FILENAME = "config.ini"


# 日志设置
LOG_DIR = 'log'
LEVELINFO = 'INFO'
LEVELDEBUG = 'DEBUG'
logger.add(
    Path(LOG_DIR).joinpath("{time:YYYY-MM-DD}.log"),
    rotation="00:00",
    encoding="utf-8",
    enqueue=True,
    retention="180 days",
    level=LEVELINFO)

# current_working_dir = os.getcwd()
# db = DBHelp_Sqliteb.SqliteDb(db=DATABASE_FILENAME)
# datatable = db.select_db('SELECT 号码 FROM USERS where ')

configs = {

}
db = DBHelp_Sqlite.SqliteDb(db=DATABASE_FILENAME)
def split_string(input_str):
    """
    将输入字符串按顿号拆分，如果不含顿号则返回整个字符串
    
    参数:
        input_str (str): 要处理的字符串
        
    返回:
        list: 拆分后的结果列表
    """
    if "/" in input_str:
        # 找到第一个顿号的位置
        index = input_str.find("/")
        # 返回顿号后面的所有字符
        return input_str[index+1:]
    else:
        return input_str

def read_configs(filename=CFG_FILENAME, configs=configs):
    print('reading configs')
    try:
        with open(filename, 'r', encoding='utf-8', errors="ignore") as f:
            lines = f.readlines()
        for line in lines:
            # 去除无用行
            # print(line)
            if line.strip().startswith('#') or '=' not in line:
                continue
            lv = line[0:line.index('=')].strip()
            rv = line[line.index('=') + 1:].strip()

            # 使用了不支持的配置
            if lv not in configs:
                print(f'unsupported config {lv} = {rv}')
                continue
            # 将读取的配置字符串转为对应类型并存入 config 字典
            try:
                if type(configs[lv]) == bool:
                    configs[lv] = True if rv.lower() == 'true' else False
                elif type(configs[lv]) == list:
                    rv = rv.split(',')
                    configs[lv] = type(configs[lv])(rv)
                else:
                    configs[lv] = type(configs[lv])(rv)
                print(f'config {lv} = {rv}')
            except ValueError as e:
                logger.error(f"配置项 {lv} 的值 {rv} 无法转换为 {type(configs[lv])} 类型: {e}")
                continue
        return configs
    except FileNotFoundError:
        logger.error(f"配置文件 {filename} 未找到")
        return None
    except Exception as e:
        logger.error(f"读取配置文件 {filename} 时出错: {e}\n{traceback.format_exc()}")
        return None

class Settings:
    """
    设置类

    """

    def __init__(self, config):

        self.nbl_server = config["nbl_server"]
        # 门禁服务器地址
        self.nbl_port = config["nbl_port"]
        # 门禁服务器端口
        self.nbl_doors_in = config["nbl_doors_in"]
        # 门禁ID,多个用逗号隔开
        self.nbl_doors_out = config["nbl_doors_out"]
        # 门禁ID,多个用逗号隔开
        self.nbl_doors = self.nbl_doors_in + self.nbl_doors_out
class WhiteNumbers:
    """
    白名单号码类,白名单号码,userlist,
    进出字典：包含SEQENQ序号,换卡事件方向(1 or 2),字符串
    """

    def __init__(self):

        # 用户列表,全局变量
        self.seqnq = 0


    def init_seqnq(self):
        """
        初始化序号
        :return:
        """
        self.seqnq = 0

    def get_seqnq(self):
        """
        获取序号,自增加1
        :return:序号
        """
        self.seqnq += 1
        if self.seqnq > 65535:
            self.seqnq = 1
        return self.seqnq


def set_quickedit_mode(enable=True):
    """
    这个函数接收一个参数enable 无返回值。
    如果enable为True,则启用快速编辑模式,否则禁用。
    :param x: 第一个加数
    :type enable: bool
    :return: null
    :rtype: null
    """
    # 定义 registry 键的路径
    path = r'Console'
    # 打开 registry 键
    with winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, winreg.KEY_WRITE) as key:
        if enable:
            winreg.SetValueEx(key, "QuickEdit", 0, winreg.REG_DWORD, 1)
        else:
            winreg.SetValueEx(key, "QuickEdit", 0, winreg.REG_DWORD, 0)


def connect_to_server():
    """
    # 创建 socket 对象
    """
    for attempt in range(MAX_CONNECT_RETRIES):
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client_socket.settimeout(10)  # 设置连接超时时间为 10 秒
        try:
            client_socket.connect((s_object.nbl_server, s_object.nbl_port))
            logger.success(f"服务器 {s_object.nbl_server}:{s_object.nbl_port} 建立连接成功")
            return client_socket
        except (ConnectionRefusedError, ConnectionResetError) as e:
            logger.error(f"服务器 {s_object.nbl_server}:{s_object.nbl_port} 连接被拒绝，第 {attempt + 1} 次尝试: {e}")
        except TimeoutError as e:
            logger.error(f"服务器 {s_object.nbl_server}:{s_object.nbl_port} 连接超时，请检查网络连接，第 {attempt + 1} 次尝试: {e}")
        except Exception as e:
            logger.error(f"连接服务器时出现未知错误，第 {attempt + 1} 次尝试: {e}")

        client_socket.close()
        if attempt < MAX_CONNECT_RETRIES - 1:
            time.sleep(CONNECT_RETRY_DELAY)  # 等待一段时间后重试

    logger.error(f"达到最大重试次数，无法连接到服务器 {s_object.nbl_server}:{s_object.nbl_port}")
    return False


def send_data(client_socket, data):
    """
    发送数据到服务器
    :param client_socket: 客户端 socket 对象
    :param data: 要发送的数据
    :return: None
    """
    try:
        client_socket.sendall(data)
        logger.success(f"消息发送成功: {data}")
    except Exception as e:
        logger.error(f"发送失败: {e}")


def action_door(data):
    """
    处理门禁事件
    :param data: 接收到的数据
    """
    try:
        pattern_emp_name = re.compile(r"<EmpName>(.*?)</EmpName>")
        pattern_mobilephone = re.compile(r"<MobilePhone>(.*?)</MobilePhone>")
        pattern_door_no = re.compile(r"<DoorNo>(.*?)</DoorNo>")
        pattern_emp_no = re.compile(r"<EmpNo>(.*?)</EmpNo>")
        # attern_visitor_type= re.compile(r"<VisitorType>(.*?)</VisitorType>")
        emp_name_match = pattern_emp_name.search(data)
        mobilephone_match = pattern_mobilephone.search(data)
        door_no_match = pattern_door_no.search(data)
        emp_no_match = pattern_emp_no.search(data)
        # visitor_type_match = pattern_visitor_type.search(data)
        emp_no_match = pattern_emp_no.search(data)
        emp_name = emp_name_match.group(1) if emp_name_match else "未找到EmpName"
        mobilephone = (mobilephone_match.group(
            1) if mobilephone_match else "未找到mobilephone")
        door_no = door_no_match.group(1) if door_no_match else ""
        emp_no = (
            emp_no_match.group(1) if emp_no_match else ""
        )
        # visitor_type_match = visitor_type_match.group(1) if visitor_type_match else ""
        if emp_no == '00000000' or emp_no == '':
            logger.info(f"外来人员或空数据：{emp_name}({mobilephone}),不动作")
            return 1
        else:
            if mobilephone:

                if door_no in s_object.nbl_doors_in:
                    print(f"进入人员：{emp_name}({mobilephone})")
                if door_no in s_object.nbl_doors_out:
                    print(f"退出人员：{emp_name}({mobilephone})")
            else:
                logger.warning(
                    f"DoorEvent未找到手机号,不动作: {emp_name}({mobilephone})"
                )
            return 1
    except Exception as e:
        logger.error(f"action_door函数报错: {e}")
        return e


def action_card(client_socket, data):
    """
    处理换卡事件
    :param client_socket: 客户端 socket 对象
    :param data: 接收到的数据
    """
    try:
        pattern_emp_name = re.compile(r"<EmpName>(.*?)</EmpName>")
        pattern_emp_no = re.compile(r"<EmpNo>(.*?)</EmpNo>")
        pattern_io_state = re.compile(r"<IoState>(\d+)</IoState>")
        emp_name_match = pattern_emp_name.search(data)
        emp_no_match = pattern_emp_no.search(data)
        io_state_match = pattern_io_state.search(data)
        emp_name = emp_name_match.group(1) if emp_name_match else "未找到EmpName"
        emp_no = (
            emp_no_match.group(1) if emp_no_match else ""
        )
        io_state = io_state_match.group(1) if io_state_match else "未找到IoState"
        # print(data)
        logger.info(
            f"换卡信息: {emp_name}({emp_no},{io_state}))"
        )
        if emp_no == '00000000' or emp_no == '':
            logger.info(f"外来人员或空数据：{emp_name},不动作")
            return io_state
        else:
            # print("io_state:",type(io_state))
            seqnq = w_object.get_seqnq()
            print("SEQNO:", seqnq)
            w_object.in_out_dict[f"{seqnq}"] = io_state
            '''if  io_state=='1':
                w_object.add_in(emp_no)

            if  io_state=='2':
                w_object.add_out(emp_no)'''
            send_data(
                client_socket,
                f"""<?xml version="1.0" encoding="gb2312"?><MESSAGE NAME ="GETEMPDATA" TYPE ="REQ" SEQNO ="{seqnq}"><EmpNo>{emp_no}</EmpNo><GetParam></GetParam></MESSAGE>""".encode("gb2312"),
            )

            return io_state
    except Exception as e:
        logger.error(f"action_card函数报错: {e}")
        return e


def action_emp(data):
    """
    处理人员信息事件
    :param data: 接收到的数据
    """
    try:
        pattern_emp_name = re.compile(r"<EmpName>(.*?)</EmpName>")
        pattern_emp_no = re.compile(r"<EmpNo>(.*?)</EmpNo>")
        pattern_emp_type = re.compile(r"<EmpType>(\d+)</EmpType>")
        pattern_dept_name = re.compile(r"<DeptName>(.*?)</DeptName>")
        pattern_dept_no = re.compile(r"<DeptNo>(.*?)</DeptNo>")
        pattern_mobilephone = re.compile(r"<MobilePhone>(.*?)</MobilePhone>")
        pattern_seqnq = re.compile(r"SEQNO=\"(\d+)\"")
        emp_name_match = pattern_emp_name.search(data)
        emp_no_match = pattern_emp_no.search(data)
        emp_type_match = pattern_emp_type.search(data)
        dept_name_match = pattern_dept_name.search(data)
        dept_no_match = pattern_dept_no.search(data)
        mobilephone_match = pattern_mobilephone.search(data)
        seqnq_match = pattern_seqnq.search(data)
        emp_name = emp_name_match.group(1) if emp_name_match else "未找到EmpName"
        emp_no = (
            emp_no_match.group(1) if emp_no_match else ""
        )
        emp_type = emp_type_match.group(1) if emp_type_match else "0"
        dept_name = dept_name_match.group(1) if dept_name_match else ""
        dept_no = dept_no_match.group(1) if dept_no_match else ""
        # print(data)
        mobilephone = mobilephone_match.group(1) if mobilephone_match else ""
        # print(data)
        seqnq = seqnq_match.group(1) if seqnq_match else "0"
        print("SEQNO:", seqnq)
        io_state = w_object.in_out_dict.pop(f"{seqnq}", "0")
        print("进出门数据字典:", w_object.in_out_dict)
        logger.info(
            f"人员信息: {emp_name}({emp_no},{mobilephone},{dept_name},{dept_no},{io_state}))"
        )
        if emp_no == '' or emp_no is None:
            logger.info(f"SEQNO:{seqnq}返回空数据,不处理")
            return io_state
        else:

            if mobilephone:

                if io_state == "1":

                    with db:
                        count = db.execute_db(
                            f"update users set 内外=1 where 号码=\'{mobilephone}\'")

                    logger.info(
                        f"更新USERS表:{emp_name}({emp_no},{mobilephone},进,{count}条数据)")
                if io_state == "2":
                    with db:
                        count = db.execute_db(
                            f"update users set 内外=2 where 号码=\'{mobilephone}\'")
                    logger.info(
                        f"更新USERS表:{emp_name}({emp_no},{mobilephone},出,{count}条数据)")


            else:
                logger.warning(
                    f"EmpData未找到手机号,无法切换模式: {emp_name}({mobilephone})"
                )

            return 1
    except Exception as e:
        logger.error(f"action_emp函数报错: {e}")
        return e



def initialize_connection(client_socket, s_object):
    """
    连接后的初始化操作
    :param client_socket: 客户端 socket 对象
    :param s_object: 设置对象
    :return: 初始化是否成功
    """
    # 配置超时参数
    max_retries = 3
    timeout_seconds = 10
    retry_interval = 5

    
    print("---")
    current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
    print(f"@--{current_time}--连接成功")


    # 发送 INIT 消息
    w_object.init_seqnq()
    seqnq = w_object.get_seqnq()
    print("SEQNO:", seqnq)
    doors = ",".join(s_object.nbl_doors)
    send_data(
        client_socket,
        f"""<?xml version="1.0" encoding="gb2312"?><MESSAGE NAME="INIT" TYPE="REQ" SEQNO="{seqnq}"><SiteFilter>true</SiteFilter><FilterDoor>{doors}</FilterDoor></MESSAGE>""".encode("gb2312")
    )

    pattern_Name = re.compile(r"MESSAGE NAME=\"(.*?)\"")
    pattern_result = re.compile(r"<Result>(\d+)</Result>")
    try:
        data = client_socket.recv(1024).decode("gbk", errors='ignore')
        logger.info(data[12:])
        if not data:
            logger.warning("未接收到消息AUTH")
            return False
    except Exception as e:
        print(e)
    
    try:
        name_match = pattern_Name.search(data)
        result_match = pattern_result.search(data)
        name = name_match.group(1) if name_match else "Name"
        result = result_match.group(1) if result_match else "result"
        if name == "INIT":
            if result == "0":
                logger.success("门禁通讯初始化成功")
            else:
                logger.error("门禁通讯初始化失败")
                return False
    except :
        logger.error("解析INIT xml失败")
        return False

    time.sleep(0.1)

    # 发送 AUTH 消息
    seqnq = w_object.get_seqnq()
    print("SEQNO:", seqnq)
    send_data(
        client_socket,
        f"""<?xml version="1.0" encoding="gb2312"?><MESSAGE NAME="AUTH" TYPE ="REQ" SEQNO ="{seqnq}"><PWD></PWD></MESSAGE>""".encode("gb2312")
    )
    try:
        data = client_socket.recv(1024).decode("gbk", errors='ignore')
        logger.info(data[12:])
        if not data:
            logger.warning("未接收到消息AUTH")
            return False
    except Exception as e:
        print(e)


    try:
        name_match = pattern_Name.search(data)
        result_match = pattern_result.search(data)
        name = name_match.group(1) if name_match else "Name"
        result = result_match.group(1) if result_match else "result"
        if name == "AUTH":
            if result == "0":
                logger.success("门禁通讯认证成功")
            else:
                logger.error("门禁通讯认证失败")
                return False
    except :
        logger.error("解析AUTH xml失败")
        return False

    return True
def reconnect():
    """
    尝试重新连接到服务器
    :return: 客户端 socket 对象或 False
    """
    max_retries = 10
    retry_delay = 5
    for i in range(max_retries):
        logger.info(f"尝试重新连接，第 {i + 1} 次重试")
        client_socket = connect_to_server()
        if client_socket:
            if initialize_connection(client_socket, w_object, s_object):
                logger.success("重新连接并初始化成功")
                return client_socket
            else:
                client_socket.close()
        time.sleep(retry_delay)
    logger.error("达到最大重试次数，无法重新连接")
    return False

def receive_data(client_socket):
    """
    接收并处理服务器数据
    :param client_socket: 客户端 socket 对象
    :return: 接收到的数据或 False
    """
    client_socket.settimeout(5)  # 设置接收数据超时时间为 5 秒
    while True:
        try:
            data = client_socket.recv(1024).decode("gbk", errors='ignore')
            if not data:
                
                
                logger.warning("未接收到消息，尝试重新连接")
                client_socket.close()
                new_socket = reconnect()
                if new_socket:
                    client_socket = new_socket
                    continue  # 重连成功，继续接收数据
                else:
                    break  # 重连失败，退出循环
                
            if "ACTIVE" in data:
                print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}--收到心跳包:{data[12:]}")
            if "DOOREVENT" in data:
                logger.info("进出数据,准备写入log:" + data)
                result = action_door(data)
                if result != 1:
                    logger.error(f"DOOREVENT执行动作失败:{result}")
            if "SWAPCARDEVENT" in data:
                logger.info("换卡数据,准备写入log:" + data)
                result = action_card(client_socket, data)
                if result == '1':
                    print("进入")
                elif result == '2':
                    print("出门")
                else:
                    logger.error(f"SWAPCARDEVENT执行动作失败:{result}")
            if "GETEMPDATA" in data:
                logger.info("人员数据,准备写入log:" + data)
                result = action_emp(data)
                if result != 1:
                    logger.error(f"GETEMPDATA执行动作失败:{result}")
        except socket.timeout:
            continue  # 超时后继续尝试接收数据
        except Exception as e:
            logger.error(f"服务器关闭连接: {e}")
            client_socket.close()
            new_socket = reconnect()
            if new_socket:
                client_socket = new_socket
                client_socket.settimeout(5)  # 重新设置超时时间
                continue  # 重连成功，继续接收数据
            else:
                break  # 重连失败，退出循环
def event_listener(event):
    """
    事件监听器
    :param event: 事件对象"""
    if event.exception:
        logger.error(f"任务 {event.job_id} 出错: {event.exception}")
    else:
        logger.info(f"任务 {event.job_id} 执行成功")
def main():
    """
    主函数
    """
    # 连接到服务器
    client_socket = connect_to_server()
    if client_socket:
        if initialize_connection(client_socket, w_object, s_object):
            try:
                # 创建一个线程来运行 receive_data 函数
                receive_thread = threading.Thread(target=receive_data, args=(client_socket,))
                # 启动线程
                receive_thread.start()

                # 主线程可以继续执行其他任务
                # 这里可以添加主线程的其他逻辑
            except Exception as e:
                logger.error(f"启动接收线程时出错: {e}")
        else:
            client_socket.close()
    else:
        logger.error("无法连接到服务器")
    
    # 修改为 BackgroundScheduler
    scheduler = BackgroundScheduler(timezone='Asia/Shanghai')
    scheduler.add_listener(event_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
    print('定时脚本-->>> 定时启动中')

    try:
        max_retries = 5  # 最大重试次数
        retry_delay = 10  # 重试间隔(秒)
        
        for attempt in range(max_retries):
            try:
                scheduler.start()
                logger.success('定时脚本-->>> 启动完毕')
                break
            except Exception as e:
                if attempt < max_retries - 1:
                    logger.warning(f'启动失败，第{attempt+1}次重试... 错误: {str(e)}')
                    time.sleep(retry_delay)
                else:
                    logger.critical(f'启动失败，已达最大重试次数: {str(e)}')
                    raise

        # 阻塞主线程
        while True:
            time.sleep(3600)  # 每小时检查一次
    except (KeyboardInterrupt, SystemExit, Exception):
        scheduler.shutdown()
        logger.error('定时脚本-->>> 异常关闭')
        # 添加清理资源的代码（如果有）
    finally:
        if scheduler.running:
            scheduler.shutdown()
    

app = Flask(__name__,template_folder='templates')



# 配置缓存
'''cache = Cache(app, config={
    'CACHE_TYPE': 'simple',
    'CACHE_DEFAULT_TIMEOUT': 600  # 缓存时间为 60 秒
})'''



       



def split_string(input_str):
    """
    将输入字符串按顿号拆分，如果不含顿号则返回整个字符串
    
    参数:
        input_str (str): 要处理的字符串
        
    返回:
        list: 拆分后的结果列表
    """
    if "/" in input_str:
        # 找到第一个顿号的位置
        index = input_str.find("/")
        # 返回顿号后面的所有字符
        return input_str[index+1:]
    else:
        return input_str



def convert_timestamp_to_text(timestamp_ms, format_str='%Y-%m-%d %H:%M:%S'):
    """
    将毫秒时间戳转换为日期时间文本
    
    Args:
        timestamp_ms: 毫秒时间戳
        format_str: 日期时间格式字符串
    
    Returns:
        str: 格式化后的日期时间文本
    """
    if timestamp_ms is None:
        return None
    try:
        # 转换为秒并创建datetime对象
        dt = datetime.fromtimestamp(timestamp_ms / 1000)
        return dt.strftime(format_str)
    except (ValueError, TypeError) as e:
        print(f"转换错误: {e}")
        return None
    
@app.route('/', methods=['GET', 'POST'])
def device_status():

    # 获取用户数据
    #db = DBHelp_Sqlite.SqliteDb(db=DATABASE_FILENAME)
    user_query = """
        SELECT 部门 AS DeptName, 姓名 AS name, 号码 AS phone, 
            设备内码 AS deviceID, 
            CASE 内外 WHEN 1 THEN '内' ELSE '外' END AS status 
            FROM users 
            ORDER BY 部门, 姓名
    """
    with db:
        userdf = pd.DataFrame(db.select_db(user_query),columns=['DeptName','name','phone','deviceID','status'])
        userdf['DeptName']=userdf['DeptName'].apply(split_string)
        #userdf = userdf[userdf['DeptName'] != '监狱领导']
        # 获取部门数据
        dept_query = "SELECT name AS DeptName, deptid FROM DEPARTMENT ORDER BY deptid"
        deptdf = pd.DataFrame(db.select_db(dept_query),columns=['DeptName','deptid'])
        deptdf['DeptName'] = deptdf['DeptName'].apply(split_string)
    
    # 处理筛选请求
    selected_dept = request.form.get('dept_filter', '')
    table_data = []
    current_dept = "所有部门"
    # 处理所有部门情况
    if selected_dept == '所有部门' or not selected_dept:
        # 显示所有用户的基本信息
        table_data = userdf.fillna('').to_dict('records')
        current_dept = "所有部门"
    elif selected_dept:
   
        # 获取选中部门的设备状态
        dept_row = deptdf[deptdf['DeptName'] == selected_dept]
        if not dept_row.empty:
            deptid = dept_row.iloc[0]['deptid']
            
            
            # 只显示选中部门的用户
            filtered_df = userdf[userdf['DeptName'] == selected_dept]
            # 转换为字典列表
            table_data = filtered_df.to_dict('records')
            current_dept = selected_dept
    
    # 准备部门筛选选项
    departments = ['所有部门'] + deptdf['DeptName'].unique().tolist()
    
    return render_template('device_status.html', 
                           table_data=table_data,
                           departments=departments,
                           selected_dept=selected_dept,
                           current_dept=current_dept,
                           record_count=len(table_data))

# 生产环境配置
app.config.update(
    SECRET_KEY=os.environ.get('FLASK_SECRET_KEY', 'your-strong-secret-key'),
    ENV='production',
    DEBUG=False
)
class FlaskThreadedServer:
    def __init__(self, host='0.0.0.0', port=5000):
        self.host = host
        self.port = port
        self.server = None
        self.thread = None
        self._stop_event = threading.Event()
        
        # 设置信号处理
        signal.signal(signal.SIGINT, self.signal_handler)
        signal.signal(signal.SIGTERM, self.signal_handler)
    
    def signal_handler(self, signum, frame):
        """处理终止信号"""
        logger.info(f"Received signal {signum}, shutting down...")
        self.stop_server()
        sys.exit(0)
    
    def run_server(self):
        """运行 Waitress 服务器"""
        logger.info(f"Starting production server on {self.host}:{self.port}")
        serve(
            app, 
            host=self.host, 
            port=self.port,
            threads=5,  # 根据需求调整线程数
            ident=None  # 隐藏服务器标识
        )
        logger.info("Server has stopped")
    
    def start(self):
        """启动服务器线程"""
        if self.thread and self.thread.is_alive():
            logger.warning("Server is already running")
            return
        
        self._stop_event.clear()
        self.thread = threading.Thread(target=self.run_server, daemon=True)
        self.thread.start()
        logger.info("Flask server thread started")
    
    def stop_server(self):
        """停止服务器"""
        if self.server:
            try:
                logger.info("Shutting down server...")
                self.server.close()
            except Exception as e:
                logger.error(f"Error shutting down server: {e}")
        
        self._stop_event.set()
        logger.info("Server shutdown initiated")

    def is_running(self):
        """检查服务器是否在运行"""
        return self.thread and self.thread.is_alive()

if __name__ == "__main__":
    """
    纽贝尔
    """
    # 示例：禁用快速编辑模式
    # set_quickedit_mode(False)
    try:
        c = read_configs(CFG_FILENAME,)
        # c = json.loads(c)
        # 读取配置文件
        print(c)
        s_object = Settings(c)
        # 初始化设置
    except Exception as e:
        print("配置文件读取失败:", end='')
        print(e)
        quit()
    print("door all:", s_object.nbl_doors)
    w_object = WhiteNumbers()
    print('*' * 32)
    # 创建并启动Flask服务器
    flask_server = FlaskThreadedServer(port=8080)
    flask_server.start()

    main()

